package com.h2cloud.JUCTest.patten;

import org.apache.poi.ss.formula.functions.T;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

class SyncWaitNotify {
	// 等待标记
	private int flag;
	// 循环次数
	private int loopNumber;

	public SyncWaitNotify(int flag, int loopNumber) {
		this.flag = flag;
		this.loopNumber = loopNumber;
	}

	/**
	 * @param curFlag 等待标记
	 * @param nextFlag 下一个标记
	 * @param str      输出内容
	 */
	public void print(int curFlag, int nextFlag, String str) {
		for (int i = 0; i < loopNumber; i++) {
			synchronized (this) {
				while (this.flag != curFlag) {
					try {
						this.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.print(str);
				flag = nextFlag;
				this.notifyAll();
			}
		}
	}
}

class SyncLock {
	ReentrantLock lock = new ReentrantLock();
	Condition waitSet = lock.newCondition();

	int flag;
	int loopNum;

	public SyncLock(int flag, int loopNum) {
		this.flag = flag;
		this.loopNum = loopNum;
	}

	public void print(int curFlag, int nextFlag, String str) {
		for (int i = 0; i < loopNum; i++) {
			lock.lock();
			try {
				while (flag != curFlag) {
					waitSet.await();
				}
				System.out.print(str);
				flag = nextFlag;
				waitSet.signalAll();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
	}
}

class ParkAndUnPark {

	private int loopNumber;

	public ParkAndUnPark(int loopNumber) {
		this.loopNumber = loopNumber;
	}

	public void run(String str, Thread nextThread) {
		for (int i = 0; i < loopNumber; i++) {
			LockSupport.park();
			System.out.print(str);
			LockSupport.unpark(nextThread);
		}
	}
}


public class TestOrder {
	static Thread t1, t2, t3;

	private static void test3() {
		ParkAndUnPark obj = new ParkAndUnPark(5);
		t1 = new Thread(() -> {
			obj.run("a", t2);
		});
		t2 = new Thread(() -> {
			obj.run("b", t3);
		});
		t3 = new Thread(() -> {
			obj.run("c\n", t1);
		});
		t1.start();
		t2.start();
		t3.start();
		LockSupport.unpark(t1);
	}

	public static void main(String[] args) {
		test2();
	}

	private static void test2() {
		SyncLock syncLock = new SyncLock(1, 5);
		new Thread(() -> {
			syncLock.print(1, 2, "a");
		}).start();
		new Thread(() -> {
			syncLock.print(2, 3, "b");
		}).start();
		new Thread(() -> {
			syncLock.print(3, 1, "c\n");
		}).start();
	}

	private static void test1() {
		SyncWaitNotify syncWaitNotify = new SyncWaitNotify(1, 5);
		new Thread(() -> {
			syncWaitNotify.print(1, 2, "a");
		}).start();
		new Thread(() -> {
			syncWaitNotify.print(2, 3, "b");
		}).start();
		new Thread(() -> {
			syncWaitNotify.print(3, 1, "c\n");
		}).start();
	}

}
